﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using LibCommon;
using LibGUI.Chat;
using LibGUI.MainForm;
using LibRTC;
using LibRTC.Core;
using LibRTC.Core.MessageMap.MediaEvent;
using LibRTC.Core.MessageMap.MessagingEvent;
using LibRTC.Core.MessageMap.SessionStateChangeEvent;
using LibRTC.Interface;
using RTCCore;

namespace LibGUI.Schedule
{
    public class MessageDispatcher : ISessionNew,IVideoEvent
    {
        // i want to make it a singleton
        private static MessageDispatcher _instance = null;
        private static ILogger LOGGER = LoggerFactory.GetLogger("MessageDispatcher",null);

        private RTCSystem rtcSystem = RTCSystem.GetInstance();

        private Dictionary<string, ChatForm> _chatFormDict = new Dictionary<string, ChatForm>();

        // we only allow one video chat form
        private ChatForm videoChatForm = null;

        #region Fields
        private Form parentForm;
        private IRTCCoreOperations rtcCoreOperations;

        public void SetParentForm(Form parentForm)
        {
            this.parentForm = parentForm;
        }

        public void SetRTCCoreOperations(IRTCCoreOperations operations)
        {
            this.rtcCoreOperations = operations;
        }

        #endregion

        public MessageDispatcher()
        {
            _instance = this;
        }

        public static MessageDispatcher GetInstance()
        {
            if(null == _instance)
            {
                _instance = new MessageDispatcher();
            }

            return _instance;
        }

        public bool IsChatFormExist(string remoteUserURI)
        {
            return _chatFormDict.ContainsKey(remoteUserURI);
        }

        public ChatForm GetChatForm(string remoteUserURI)
        {
            if(IsChatFormExist(remoteUserURI))
            {
                return _chatFormDict[remoteUserURI];
            }
            return null;
        }

        public void AddChatForm(string remoteUserURI,ChatForm form)
        {
            if(_chatFormDict.ContainsKey(remoteUserURI))
            {
                LOGGER.LogError("Duplicate ChatForm : "+remoteUserURI);
            }

            _chatFormDict.Add(remoteUserURI,form);    
        }

        public ChatForm CreateAddChatForm(MetaDataChat metaDataChat)
        {
            string remoteUserURI = metaDataChat.remoteUserURI;

            if (_chatFormDict.ContainsKey(remoteUserURI))
            {
                LOGGER.LogError("Duplicate ChatForm : " + remoteUserURI);
                return _chatFormDict[remoteUserURI];
            }

            ChatForm chatForm = new ChatForm(metaDataChat, this, this.rtcCoreOperations);

            // add to dictionary
            AddChatForm(remoteUserURI, chatForm);

            //show chatform
            chatForm.Show(parentForm);

            return chatForm;
        }

        public ChatForm CreateAddChatForm(string localUserName, string localUserUri,
                                string remoteUserName, string remoteUserUri)
        {
            MetaDataChat metaDataChat = new MetaDataChat();
            metaDataChat.imSession = null;
            metaDataChat.localUserName = localUserName;
            metaDataChat.localUserURI = localUserUri;
            metaDataChat.remoteUserURI = remoteUserUri;
            metaDataChat.remoteUserName = remoteUserName;

            ChatForm chatForm = CreateAddChatForm(metaDataChat);

            chatForm.BringToFront();

            return chatForm;
        }

        public void RemoveChatForm(string remoteUserURI)
        {
            if(!_chatFormDict.ContainsKey(remoteUserURI))
            {
                LOGGER.LogError("ChatForm does not exist for "+remoteUserURI);
                return;
            }
            ChatForm chatForm;
            _chatFormDict.TryGetValue(remoteUserURI,out chatForm);
            Debug.Assert(null != chatForm);
            _chatFormDict.Remove(remoteUserURI);

            if(videoChatForm == chatForm) {
                videoChatForm = null;
            }

        }

        public void SetVideoChatForm(ChatForm chatForm) {
            Debug.Assert(null != chatForm);
            Debug.Assert(null == videoChatForm);

            videoChatForm = chatForm;
        }

        public void OnIMSessionNew(string remoteUserName, string remoteUserURI, IRTCSession imSession) {

            ChatForm chatForm = GetChatForm(remoteUserURI);

            if (null == chatForm)
            {
                //construct metadata
                MetaDataChat metaDataChat = new MetaDataChat();
                metaDataChat.imSession = imSession;
                metaDataChat.remoteUserURI = remoteUserURI;
                metaDataChat.remoteUserName = remoteUserName;
                metaDataChat.localUserName = rtcSystem.LocalUserName;
                metaDataChat.localUserURI = rtcSystem.LocalUserURI;

                chatForm = new ChatForm(metaDataChat, this, rtcCoreOperations);

                // add to dictionary
                AddChatForm(remoteUserURI, chatForm);

                //show chatform
                chatForm.Show(parentForm);
            }
            else
            {
                chatForm.SetIMSession(imSession);
            }
            
        }

        public void OnVideoSessionNew(string remoteUserName, string remoteUserURI, IRTCSession videoSession) {
            IncomingCallDialog incomingCallDialog = new IncomingCallDialog();

            incomingCallDialog.ShowDialog(parentForm);

            if (DialogResult.Cancel == incomingCallDialog.DialogResult)
            {
                videoSession.Terminate(RTC_TERMINATE_REASON.RTCTR_REJECT);
                return;
            }

            //user accept the call
            videoSession.Answer();

            //stop the video if there is one exist
            if (null != videoChatForm)
            {
                videoChatForm.StopVideoChat();
                videoChatForm = null;
            }

            ChatForm chatForm = GetChatForm(remoteUserURI);

            if (null == chatForm)
            {
                //construct metadata
                MetaDataChat metaDataChat = new MetaDataChat();
                metaDataChat.videoSession = videoSession;
                metaDataChat.remoteUserURI = remoteUserURI;
                metaDataChat.remoteUserName = remoteUserName;
                metaDataChat.localUserName = rtcSystem.LocalUserName;
                metaDataChat.localUserURI = rtcSystem.LocalUserURI;

                chatForm = new ChatForm(metaDataChat, this, rtcCoreOperations);

                // add to dictionary
                AddChatForm(remoteUserURI, chatForm);

                //show chatform
                chatForm.Show(parentForm);
            }
            else
            {
                chatForm.SetVideoSession(videoSession);
            }

            videoChatForm = chatForm;
        }

        public void OnStartSendVideo(RTC_VIDEO_DEVICE device, int mediaCapabilities, IVideoWindow videoWindow) {
            
            Debug.Assert(null != videoChatForm);

            if(null != videoWindow) {
                videoChatForm.SetPreviewWindow(videoWindow);
            }

        }

        public void OnStopSendVideo() {
            if (null != videoChatForm) {
                videoChatForm.RemovePreviewWindow();
            }
        }

        public void OnStartReceiveVideo(RTC_VIDEO_DEVICE device, int mediaCapabilities, IVideoWindow videoWindow) {
            Debug.Assert(null != videoChatForm);

            if (null != videoWindow)
            {
                videoChatForm.SetReceiveWindow(videoWindow);
            }
        }

        public void OnStopReceiveVideo() {
            if (null != videoChatForm) {
                videoChatForm.RemoveReceiveWindow();
            }
        }

    }
}
